﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Dycox;
using System.Runtime.Serialization;

namespace Dycox.ComponentModel
{
    [DataContract]
    public class MessageSet : Collection<MessageEntry>, ICollection<MessageEntry>
    {
        public MessageSet()
        {
        }

        public bool Success
        {
            get { return !_cancel && !this.Any(o => o.Kind > MessageKind.Information); }
        }

        [DataMember(Name = "cancel", EmitDefaultValue = false)]
        bool _cancel;

        public bool Cancel
        {
            get { return _cancel; }
            set
            {
                if (value)
                {
                    base.Clear();
                }
                _cancel = value;
            }
        }

        public void SetReadOnly()
        {
            _cancel = true;
        }

        public MessageKind Level
        {
            get
            {
                if (_cancel || this.Count == 0) return MessageKind.Information;
                return this.Select(o => o.Kind).Max();
            }
        }
        
        /// <summary>
        /// 添加一条指定种类的消息到此集合，同时可指定一个附加的对象。
        /// </summary>
        /// <param name="message">消息内容</param>
        /// <param name="kind">消息种类</param>
        /// <param name="tag">附加的数据</param>
        /// <returns></returns>
        public MessageEntry Add(string message, MessageKind kind, object tag)
        {
            MessageEntry item = new MessageEntry(message, kind, tag);
            this.Add(item);
            return item;
        }

        /// <summary>
        /// 添加一条指定类型的消息到此集合。
        /// </summary>
        /// <param name="message">消息的内容</param>
        /// <param name="kind">消息的类型</param>
        /// <returns></returns>
        public MessageEntry Add(string message, MessageKind kind)
        {
            return this.Add(message, kind, null);
        }

        /// <summary>
        /// 添加一条消息到此集合。
        /// </summary>
        /// <param name="message">消息内容</param>
        /// <returns></returns>
        public MessageEntry Add(string message)
        {
            return this.Add(message, MessageKind.Information);
        }


        /// <summary>
        /// 添加一条错误消息到此集合。
        /// </summary>
        /// <param name="error"></param>
        /// <returns></returns>
        public MessageEntry Add(Exception error)
        {
            var item = new MessageEntry(error);
            this.Add(item);
            return item;
        }

        bool ICollection<MessageEntry>.IsReadOnly
        {
            get { return _cancel; }
        }

        protected override void InsertItem(int index, MessageEntry item)
        {
            if (!_cancel)
                base.InsertItem(index, item);
        }

        private static readonly string MessageKindMarks = "-*!";

        public override string ToString()
        {
            return this.ToString(null);
        }

        public string ToString(MessageKind kind)
        {
            return this.ToString(new MessageKind?(kind));
        }

        private string ToString(MessageKind? kind)
        {
            int count = this.Count;
            if (count > 0)
            {
                StringBuilder text = new StringBuilder();
                foreach (var item in this.OrderByDescending(o => o.Kind))
                {
                    if (kind == null || item.Kind == kind.Value)
                    {
                        if (text.Length > 0)
                        {
                            text.AppendLine();
                        }
                        if (count > 1 && kind == null)
                        {
                            text.Append(MessageKindMarks[(int)item.Kind]);
                            text.Append(' ');
                        }
                        text.Append(item.Text);
                    }
                }
                return text.ToString();
            }
            else
                return _cancel ? "已取消" : this.Level.GetText();
        }

        public void AddRange(IEnumerable<MessageEntry> coll)
        {
            if (coll == null)
                throw new ArgumentNullException("coll");

            if (coll == this)
                throw new ArgumentException("The source collection is current object.");

            foreach (var entry in coll)
                this.Add(entry);
        }
    }

    [DataContract]
    public class MessageEntry
    {
        [DataMember(Name = "msg")]
        private string _message;

        public string Text
        {
            get { return _message; }
        }

        [IgnoreDataMember]
        private object _tag;

        public object Tag
        {
            get { return _tag; }
            set { _tag = value; }
        }

        [DataMember(Name = "short", EmitDefaultValue = false), DefaultValue(null)]
        private string _shortText;

        public string ShortText
        {
            get { return _shortText; }
            set { _shortText = value; }
        }

        [DataMember(Name = "kind", EmitDefaultValue = false)]
        [DefaultValue(typeof(MessageKind), "Information")]
        private MessageKind _kind;

        public MessageKind Kind
        {
            get { return _kind; }
        }

        private MessageEntry()
        {

        }

        public MessageEntry(string message, MessageKind kind, object tag)
        {
            this._message = message;
            this._tag = tag;
            this._kind = kind;
        }

        public MessageEntry(string message, MessageKind kind)
            : this(message, kind, null)
        {

        }

        public MessageEntry(Exception error)
            : this(error.Message, MessageKind.Error, error)
        {
        }
    }

    public enum MessageKind
    {
        [Description("信息")]
        Information,
        [Description("警告")]
        Warning,
        [Description("错误")]
        Error
    }
}
